package com.google.code.proto.streamio;

import com.google.protobuf.CodedOutputStream;
import com.google.protobuf.GeneratedMessage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import java.util.logging.Logger;

/**
 * A writer for an output stream of Google protocol buffer generated messages.
 * <br />
 * <br />
 * <b>Usage:</b><br />
 * {@code List<YourProtocolBufferMessage> messages = getGPBMessages...}
 * <br />
 * {@code PBStreamWriter.writeToStream(out, messages); }
 *
 * @author nichole
 */
public class PBStreamWriter {

    private static Logger log = Logger.getLogger(PBStreamWriter.class.getName());

    /**
     * Write GeneratedMessages to the given output stream.
     *
     * It uses a byte marker and array for delimiting messages.
     * Note the default here is to use the bytemarker for unsigned bytes (only uses range 0-127).
     *
     * @param out output stream being written to
     * @param messages messages generated by Google's protocol buffer
     * @throws IOException
     */
    public static void writeToStream(OutputStream out, List<? extends GeneratedMessage> messages) throws IOException {

         writeToStream(out, messages, ByteOption.UNSIGNED);
    }

    /**
     * Write GeneratedMessages to the given output stream,
     * and use the a specialized PBWireByteMarkerHelper to write the delimiters.  This is where the
     * bytemarked for unsigned bytes can be used (this is prefered for socket to socket message passing,
     * but if your client is javascript, you will need to write and read using the default
     *
     * @param out output stream being written to
     * @param messages messages generated by Google's protocol buffer
     * @param byteOption option to choose signed bytes or unsigned bytes when writing to stream.  null results
     *   in a default UNSIGNED.
     *
     * @throws IOException
     */
    public static void writeToStream(OutputStream out, List<? extends GeneratedMessage> messages,
        ByteOption byteOption) throws IOException {

        IPBWireByteMarkerHelper gpbWireByteMarkerHelper = null;

        if ((byteOption == null) || (byteOption.ordinal() == ByteOption.UNSIGNED.ordinal())) {

            gpbWireByteMarkerHelper = new PBWireUnsignedByteMarkerHelper();

        } else {

            gpbWireByteMarkerHelper = new PBWireUnsignedByteMarkerHelper();
        }

        int count = 1;

        for (GeneratedMessage message : messages) {

            byte[] delimiter = gpbWireByteMarkerHelper.createMessageDelimiter(message);

            out.write(delimiter);

            CodedOutputStream cos = CodedOutputStream.newInstance(out);
            /*cos.writeUInt32NoTag(count);<=*/
            message.writeTo(cos);
            cos.flush();
            out.flush();

            count++;
        }
    }

}
